﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using System.Linq;
using OrderService.Utils;

namespace OrderService
{
    [Serializable]
    public class OrderServiceImplementation : IOrderContract
    {
        private string ConnectionString;
        private List<Order> list;
        private static readonly object Locker = new object();

        public OrderServiceImplementation()
        {
            ConnectionString = ConfigurationManager.ConnectionStrings["DatabaseContext"].ConnectionString;
        }

        public bool IsAvailable()
        {
            using(SqlConnection connect = new SqlConnection(ConnectionString))
            {
                connect.Open();
                return connect.State == ConnectionState.Open;
            }
        }

        public void SetPayment(Order orderItem, int transactionId, bool result)
        {
            Payment item = orderItem.Payments.FirstOrDefault(e => e.TransactionId == transactionId);
            if (item != null)
            {
                item.Processed = result;

                //TODO:
                //update to database
            }
        }

        public Order GetOrder()
        {
            lock(Locker)
            {
                if (list == null || list.Count == 0)
                {
                    list = GetOrders();
                }

                if (list.Count == 0)
                {
                    LogMessage("Failed to Get orders, or no new orders!");
                    return null;
                }
                else
                {
                    Order item = list[0];
                    list.RemoveAt(0);

                    LogMessage(
                       string.Format(
                       CultureInfo.InvariantCulture,
                       "Get New Orders:{0}, Amount:{1:F2}",
                       item.OrderID,
                       item.Payments.Sum(e => e.Amount)
                       ));


                    return item;
                }
            }
        }

        private List<Order> GetOrders()
        {
            const string sql = @"EXEC dbo.Pickup_Order";

            List<Order> orders = new List<Order>();
            Order order = null;

            bool ret = DBUtil.ExecuteReader(sql, ConnectionString,
                delegate(SqlDataReader reader)
                {
                    while (reader.Read())
                    {
                        int orderId = (int)reader["OrderID"];
                        if (null == orders.Find(item => item.OrderID == orderId))
                        {
                            order = new Order(orderId);
                            orders.Add(order);
                        }
                        if (order != null)
                        {
                            int transactionId = (int)reader["PaymentId"];
                            string cardNumber = reader["CardNumber"].ToString();
                            decimal amount = (decimal)reader["Amount"];
                            order.AddPayment(transactionId, cardNumber, amount);
                        }
                    }
                }
            );

            return orders;
        }


        public bool CancelOrder(int orderNumber)
        {
            LogMessage(string.Format("Cancel Order:{0}", orderNumber));

            const string sql = @"dbo.Cancel_Order";

            SqlParameter orderId = new SqlParameter();
            orderId.ParameterName = "OrderId";
            orderId.Direction = ParameterDirection.Input;
            orderId.DbType = DbType.Int32;
            orderId.Value = orderNumber;

            return ExecuteStoreProcedure(sql, orderId);
        }

        public bool CheckProductIsAvailable(int orderNumber)
        {
            //TODO: Check Products In stock
            return true;
        }

        public bool ShipOrder(int orderNumber)
        {
            LogMessage(string.Format("Shipped Order:{0}", orderNumber));

            const string sql = @"dbo.Shipped_Order";

            SqlParameter orderId = new SqlParameter();
            orderId.ParameterName = "OrderId";
            orderId.Direction = ParameterDirection.Input;
            orderId.DbType = DbType.Int32;
            orderId.Value = orderNumber;

            return ExecuteStoreProcedure(sql, orderId);
        }

        public decimal ProduceItems(decimal quantity)
        {
            //TODO:
            return 1.0M;
        }

        public decimal ConsumeItems(decimal quantity)
        {
            //TODO:
            return 0M;
        }

        public decimal GetTotalQuantity()
        {
            //TODO:
            return 1.0M;
        }

        private void LogMessage(string message)
        {
            Console.WriteLine(message);
        }

        private bool ExecuteStoreProcedure(string sql, params SqlParameter[] parameters)
        {
            try
            {
                return DBUtil.ExecuteStoreProcedure(
                    sql,
                    ConnectionString,
                    parameters);
            }
            catch (Exception ex)
            {
                LogMessage(ex.Message);
                return false;
            }
        }
    }
}
